/*完成日志器模块：
    1. 抽象日志器基类
    2. 派生出不同的(同步日志器类 & 异步日志器类)
*/

#ifndef __M_LOGGER_H__
#define __M_LOGGER_H__

#ifndef __GNU_SOURCE
#define __GNU_SOURCE
#endif

#include "util.hpp"
#include "level.hpp"
#include "sink.hpp"
#include "format.hpp"
#include "looper.hpp"
#include <unordered_map>
#include <atomic>
#include <mutex>
#include <cstdarg>

namespace bitlog {
    class Logger {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string& logger_name,
            LogLevel::value level,
            Formatter::ptr& formatter,
            std::vector<LogSink::ptr>& sinks) : _logger_name(logger_name),
            _limit_level(level),
            _formatter(formatter),
            _sinks(sinks.begin(), sinks.end()) {}
        const std::string& name() {
            return _logger_name;
        }
        void debug(const std::string& file, size_t line, const std::string& fmt, ...) {
            // 通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            // 1.判断当前的日志是否达到了输出等级
            if (LogLevel::value::DEBUG < _limit_level) {
                return;
            }
            // 2.对fmt格式化字符串和不定参进行字符串组织，得到的日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1) {
                std::cout << "vasprintf error" << std::endl;
            }
            va_end(ap); // 清理
            serialize(LogLevel::value::DEBUG, file, line, res);
            free(res);
        }
        void info(const std::string& file, size_t line, const std::string& fmt, ...) {
            if (LogLevel::value::INFO < _limit_level) {
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1) {
                std::cout << "vasprintf error" << std::endl;
            }
            va_end(ap);
            serialize(LogLevel::value::INFO, file, line, res);
            free(res);
        }
        void warn(const std::string& file, size_t line, const std::string& fmt, ...) {
            if (LogLevel::value::WARN < _limit_level) {
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1) {
                std::cout << "vasprintf error" << std::endl;
            }
            va_end(ap);
            serialize(LogLevel::value::WARN, file, line, res);
            free(res);
        }
        void error(const std::string& file, size_t line, const std::string& fmt, ...) {
            if (LogLevel::value::ERROR < _limit_level) {
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1) {
                std::cout << "vasprintf error" << std::endl;
            }
            va_end(ap);
            serialize(LogLevel::value::ERROR, file, line, res);
            free(res);
        }
        void fatal(const std::string& file, size_t line, const std::string& fmt, ...) {
            if (LogLevel::value::FATAL < _limit_level) {
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1) {
                std::cout << "vasprintf error" << std::endl;
            }
            va_end(ap);
            serialize(LogLevel::value::FATAL, file, line, res);
            free(res);
        }

    protected:
        void serialize(LogLevel::value level, const std::string& file, size_t line, char* str) {
            // 3.构造LogMsg对象
            LogMsg msg(level, line, file, _logger_name, str);
            // 4.通过格式化工具对LogMsg进行格式化，得到格式化的日志字符串
            std::stringstream ss;
            _formatter->format(ss, msg);
            // 5.进行日志落地
            log(ss.str().c_str(), ss.str().size());
        }
        // 抽象接口完成实际的落地输出--不同的日志器会有不同的实际落地方式
        virtual void log(const char* data, size_t len) = 0;

    protected:
        std::mutex _mutex;                // 日志器互斥锁
        std::vector<LogSink::ptr> _sinks; // 日志器输出目标(落地方向)

    private:
        std::string _logger_name;                  // 日志器名称
        std::atomic<LogLevel::value> _limit_level; // 日志器日志级别
        Formatter::ptr _formatter;                 // 日志器格式化器
    };

    class SyncLogger : public Logger {
    public:
        SyncLogger(const std::string& logger_name,
            LogLevel::value level,
            Formatter::ptr& formatter,
            std::vector<LogSink::ptr>& sinks) : Logger(logger_name, level, formatter, sinks) {}

    protected:
        // 同步日志器，是将日志直接通过落地模块句柄进行日志落地
        void log(const char* data, size_t len) override {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
                return;
            for (auto& sink : _sinks) {
                sink->log(data, len);
            }
        }
    };

    class AsyncLogger : public Logger {
    public:
        AsyncLogger(const std::string& logger_name,
            LogLevel::value level,
            Formatter::ptr& formatter,
            std::vector<LogSink::ptr>& sinks,
            AsyncType looper_type) : Logger(logger_name, level, formatter, sinks),
            _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), looper_type)) {}

        // 将数据写入缓冲区
        void log(const char* data, size_t len) override {
            _looper->push(data, len);
        }
        // 设计一个实际落地函数 （将缓冲区中的数据落地）
        void realLog(Buffer& buf) {
            if (_sinks.empty()) return;
            for (auto& sink : _sinks) {
                sink->log(buf.begin(), buf.readAbleSize());
            }
        }
    private:
        AsyncLooper::ptr _looper;
    };

    enum class LoggerType {
        LOGGER_SYNC,
        LOGGER_ASYNC
    };

    /*使用建造者模式来建造日志器，而不要让用户直接去构造日志器，简化用户的使用复杂度*/
    // 1.抽象一个日志器建造者类(完成日志器对象所需零部件的构建 & 日志器的构建)
    //  1.1 设置日志器类型
    //  1.2 将不同类型日志器的创建放到同一个日志器建造者类中完成
    // LoggerBuilder类用于构建Logger实例，提供配置Logger各项属性的方法
    class LoggerBuilder {
    public:
        // 构造函数初始化_logger_type为同步日志，_limit_level为DEBUG级别
        LoggerBuilder() :
            _logger_type(LoggerType::LOGGER_SYNC),
            _limit_level(LogLevel::value::DEBUG),
            _looper_type(AsyncType::ASYNC_SAFE) {}
        // 设置日志类型
        void buildLoggerType(LoggerType type) { _logger_type = type; }
        void buildEnableUnSafeAsync() { _looper_type = AsyncType::ASYNC_UNSAFE; }
        // 设置日志名称
        void buildLoggerName(const std::string& name) { _logger_name = name; }
        // 设置日志级别
        void buildLoggerLevel(LogLevel::value level) { _limit_level = level; }
        // 设置日志格式化模式
        void buildFormatter(const std::string& pattern) { _formatter = std::make_shared<Formatter>(pattern); }
        // 模板函数，用于构建各种类型的日志沉淀器（Sink）
        template <typename SinkType, typename... Args>
        void buildSink(Args &&...args) {
            // 通过SinkFactory创建指定类型的日志沉淀器，并将其添加到_sinks列表中
            LogSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }

        // 纯虚函数，用于构建Logger实例，具体实现由子类提供
        virtual Logger::ptr build() = 0;

    protected:
        AsyncType _looper_type;           // 异步日志器类型
        LoggerType _logger_type;          // 日志类型
        std::string _logger_name;         // 日志名称
        LogLevel::value _limit_level;     // 日志级别
        Formatter::ptr _formatter;        // 日志格式化器
        std::vector<LogSink::ptr> _sinks; // 日志落地方向列表
    };

    // 2．派生出具体的建造者类---局部日志器的建造者&全局的日志器建造者（后边添加了全局单例管理器之后，将日志器添加全局管理器）
    // 定义一个本地日志构建器类，继承自LoggerBuilder基类
    class LocalLoggerBuilder : public LoggerBuilder {
    public:
        // 重写build方法以构建并返回一个Logger对象
        Logger::ptr build() override {
            // 确保_logger_name非空，因为每个Logger实例都需要一个名称
            assert(_logger_name.empty() == false);
            // 如果尚未设置格式化器，则创建一个默认的格式化器
            if (_formatter.get() == nullptr) {
                _formatter = std::make_shared<Formatter>();
            }
            // 如果没有设置任何输出目标，则构建一个默认的StdoutSink输出目标
            if (_sinks.empty()) {
                buildSink<StdoutSink>();
            }
            if (_logger_type == LoggerType::LOGGER_ASYNC) {
                return std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            // 根据当前配置创建并返回一个同步日志器对象
            return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
        }
    };

    /* 全局日志器管理器类，用于管理全局的日志器对象，并提供日志器查找等操作*/
    class LoggerManager {
    public:
        // 获取全局日志器管理器实例
        static LoggerManager& getInstance() {
            // 在c++11之后，静态局部变量的初始化是线程安全的，所以这里使用静态局部变量来保证全局日志器管理器的唯一性
            // 当静态局部变量没有构造完成之前，其他的线程进入就会阻塞
            static LoggerManager eton;
            return eton;
        }
        // 添加日志器到管理器中
        void addLogger(Logger::ptr& logger) {
            if (hasLogger(logger->name())) return;
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers[logger->name()] = logger;
        }
        // 判断日志器是否已经存在
        bool hasLogger(const std::string& name) {
            std::unique_lock<std::mutex> lock(_mutex);
            return _loggers.find(name) != _loggers.end();
        }
        // 获取日志器
        Logger::ptr getLogger(const std::string& name) {
            if (hasLogger(name)) {
                std::unique_lock<std::mutex> lock(_mutex);
                return _loggers[name];
            }
            return Logger::ptr();
        }
        // 获取默认日志器
        Logger::ptr rootLogger() {
            return _root_logger;
        }

    private:
        LoggerManager() {
            std::unique_ptr<bitlog::LoggerBuilder> builder(new bitlog::LocalLoggerBuilder());
            builder->buildLoggerName("root");
            _root_logger = builder->build();
            _loggers["root"] = _root_logger;
        }
    private:
        std::mutex _mutex;
        Logger::ptr _root_logger; // 默认日志器
        std::unordered_map<std::string, Logger::ptr> _loggers; // 日志器集合
    };

    /*设计一个全局的日志器建造者---在局部的基础上增加了一个功能：将日志器添加到单例对象中*/
    class GlobalLoggerBuilder : public LoggerBuilder {
    public:
        // 重写build方法以构建并返回一个Logger对象
        Logger::ptr build() override {
            // 确保_logger_name非空，因为每个Logger实例都需要一个名称
            assert(_logger_name.empty() == false);
            // 如果尚未设置格式化器，则创建一个默认的格式化器
            if (_formatter.get() == nullptr) {
                _formatter = std::make_shared<Formatter>();
            }
            // 如果没有设置任何输出目标，则构建一个默认的StdoutSink输出目标
            if (_sinks.empty()) {
                buildSink<StdoutSink>();
            }

            Logger::ptr logger;
            if (_logger_type == LoggerType::LOGGER_ASYNC) {
                logger = std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            else {
                logger = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
            }
            LoggerManager::getInstance().addLogger(logger);
            return logger;
        }
    };

}
#endif